/*
 * Copyright (c) Jan Šlahora (${USER}) - 2012.
 * Created in IntelliJ IDEA 10.5
 */

package statistics.tests;


import java.util.ArrayList;
import java.util.HashMap;

import statistics.Asonance.IAsonance;
import statistics.Pocitani;

/*
*   File Anova 
*   in package statistics
*   was created by slaha
*   on 27.3.12 at 12:03.
*
*/
public class Anova extends ATest implements Runnable, ITest{


  private ArrayList<ArrayList<Double>> hodnoty = new ArrayList<>();
  private ArrayList<HashMap<String, Double>> tabulka = null;
  private HashMap<String, Double> sumy = null;


  private double SA, ST, Se;
  private int n; //..počet prvků v tabulce


  public Anova(ATest hodnoty) {
    if (tabulka == null) {
      tabulka = new ArrayList<>();
    }
    for (ATest.Mereni mereni : hodnoty.getMereni()) {
      vypoctiHashMapu(mereni);
      this.hodnoty.add(mereni.getHodnoty());
      this.tabulka.add(mereni.getCharakteristiky());
    }

    run();
  }

    public Anova(IAsonance asonance) {
      this(asonance.getaTest());
  }

  public double getTestovaStatistika() {
    return ((SA/(hodnoty.size()-1)) / (Se/(n-hodnoty.size())));
  }


  private void vypoctiHashMapu(Mereni mererni) {
    //..Xi
    mererni.getCharakteristiky().put(Xi, vypoctiXi(mererni.getHodnoty()));

    //..suma Xij
    mererni.getCharakteristiky().put(sumaXij, vypoctiXij2(mererni.getHodnoty()));

    //..rozptyl Rozptyl
    mererni.getCharakteristiky().put(lnSi2, Math.log(mererni.getCharakteristiky().get(si2)));
  }

  public Anova() {
    if (tabulka == null) {
      tabulka = new ArrayList<>();
    }
  }

  @Override
  public void run() {
    sumy = new HashMap<>();

    //..suma Xi
    sumy.put(Xi, vypoctiSumu(Xi));

    //..suma Xij
    sumy.put(sumaXij, vypoctiSumu(sumaXij));

    //..suma ln si^2
    sumy.put(lnSi2, vypoctiSumu(lnSi2));

    this.n = (int) vypoctiSumu(ni);

    vypoctiS(n);
  }

  private void vypoctiS(int n) {
    this.SA = vypoctiSA(n);
    this.ST = vypoctiST(n);
    this.Se = vypoctiSe();
  }

  private double vypoctiSA(int n) {
    double prvniClen = 0d;

    double sumaXi = sumy.get(Xi);
    for (HashMap<String, Double> hm : tabulka) {
      double x_i = Math.pow(hm.get(Xi), 2);
      double n_i = (double) hm.get(ni);
      prvniClen += (x_i/n_i);
    }

    double druhyClen = Math.pow(sumy.get(Xi), 2);
    druhyClen /= n;

    double lokal_SA = prvniClen - druhyClen;

    return lokal_SA;
  }

  private double vypoctiST(int n) {
    double lokal_ST = sumy.get(sumaXij);

    double druhyClen = Math.pow(sumy.get(Xi), 2);
    druhyClen /= n;

    return (lokal_ST - druhyClen);
  }

  private double vypoctiSe() {
    double lokal_SE = 0d;

    for (int i = 0; i < tabulka.size(); i++) {
      HashMap<String, Double> hm = tabulka.get(i);
      double x_i = hm.get(prumXi);
      ArrayList<Double> al = hodnoty.get(i);
      double sumaCtvercu = 0;

      for (double d : al) {
          sumaCtvercu += Math.pow((d - x_i), 2);
        }
        lokal_SE += sumaCtvercu;
      }
    
    return lokal_SE;
  }
// pocetPrvku
// prumer
// rozptyl

  private double vypoctiXi(ArrayList<Double> hodnoty) {
    double sumaXi = 0d;

    for(double d: hodnoty) {
      sumaXi += d;
    }

    return sumaXi;
  }

  private double vypoctiPrumerXi(ArrayList<Double> hodnoty) {
    double sumaXi = 0d;

    for (double d : hodnoty) {
      sumaXi += d;
    }

    return (sumaXi/hodnoty.size());
  }

  private double vypoctiXij2(ArrayList<Double> hodnoty) {
    double sumaXi = 0d;

    for (double d : hodnoty) {
      sumaXi += Math.pow(d, 2);
    }

    return sumaXi;
  }

  private double vypoctiRozptyl(ArrayList<Double> hodnoty, double prumer) {
    double suma = 0;
    double rozptyl = ((double) 1.0d) / (hodnoty.size() - 1);

    for (double d : hodnoty) {
      double rozdil = d - prumer;
      suma += Math.pow(rozdil, 2);
    }

    rozptyl *= suma;
    //rozptyl = Math.sqrt(rozptyl);

    //System.out.println(rozptyl);

    return rozptyl;
  }

  private double vypoctiSumu(String velicina) {
    double suma = 0d;

    for (HashMap<String, Double> hm : tabulka) {
      suma += hm.get(velicina);
    }

    return suma;
  }


  //............................................
  // GETTRY
  //............................................

  public int getKvel() {
    return hodnoty.size();
  }

  public ArrayList<Double> getHodnoty(int i) {
    return hodnoty.get(i);
  }

  public double getSe() {
    return Se;
  }
  
  /**
   * Vrací počet prvků
   * @return počet naměřených prvků
   */
  public int getNvel() {
    return n;
  }

  public double getPrumer(int x) {
    return tabulka.get(x).get("prumXi");
  }


  @Override
  public String toString() {
    String r = "";
    r += "<table>";

    r += "<tr><th>Zdroj</th><th>SS</th><th>df</th><th>MS</th><th>F</th></tr>";
    r += "<tr><td><b>Rows S<sub>A</sub></a></td>" +
          "<td>" + SA + "</td><td>" + (hodnoty.size() - 1) + "</td>" +
          "<td>" + (SA / (hodnoty.size() - 1)) + "</td><td>" + getTestovaStatistika() +
          " **</td></tr>";

    r += "<tr><td><b>Error S<sub>e</sub></b></td>" +
        "<td>" + Se + "</td><td>" + (n - hodnoty.size()) + "</td>" +
        "<td>" + (Se / (n - hodnoty.size())) + "</td></tr>";

    r += "<tr><td><b>Total S<sub>T</sub></b></td>" +
        "<td>" + ((SA / (hodnoty.size() - 1)) + (Se / (n - hodnoty.size()))) + "</td>" +
        "<td>" + ((hodnoty.size() - 1) + (n - hodnoty.size())) + "</td></tr>";

    r += "</table>";


    try {
      double F = (new Pocitani().getFKritickaHodnota(getKvel() - 1, (getNvel() - getKvel()), 0.95));
      r += "<br>";

      r += "F<sub>k-1, n-k</sub>(&alpha;) = F<sub>" + getKvel() + "-1, " +
          n +"-" + getKvel() + "</sub>(&alpha;) = " + F;

      r += "<br>";

      if (F < getTestovaStatistika()) {
        r += "<b>Nulová hypotéza je zamítnuta<br>" +
            "Některé básně se liší.</b>";
      } else {
        r += "<b>Nulová hypotéza je přijata<br>" +
            "Básně se od sebe výrazně neliší.</b>";
      }
    } catch (Exception ex) {
      ex.printStackTrace();
    }
    return r;
  }

  /**
   * Vrací počet zkoumaných entit (řádků tabulky)
   * @return počet zkoumaných entit
   *
  public int getI() {
    return hodnoty.size();
  }

  **
   * Počet měření na entite i
   * @param i číslo entity
   * @return počet měření
   *
  public int getNi(int i) {
    return hodnoty.get(i).size();
  }

  /**
   * Vrátí hodnotu rozptylu na entite i
   * @param i číslo entity
   * @return rozptyl
   *
  public double getSi2(int i) {
    return tabulka.get(i).get(si2);
  }


  /**
   * Vrátí hodnotu logaritmu rozptylu na entite i
   *
   * @param i číslo entity
   * @return logaritmus rozptylu
   *
  public double getlnSi2(int i) {
    return tabulka.get(i).get(lnSi2);
  }
*/

  public static void main(String[] args) {
    ATest a = new ATest();
    ArrayList<Double> al1 = new ArrayList<>();
    ArrayList<Double> al2 = new ArrayList<>();
    ArrayList<Double> al3 = new ArrayList<>();
    ArrayList<Double> al4 = new ArrayList<>();
    ArrayList<Double> al5 = new ArrayList<>();
    
    al1.add(0.187);
    al1.add(0.836);
    al1.add(0.704);
    al1.add(0.938);
    al1.add(0.124);
    al1.add(0.678);
    al1.add(0.512);
    a.add(al1, null);


    al2.add(0.449);
    al2.add(0.769);
    al2.add(0.301);
    al2.add(0.045);
    al2.add(0.846);
    al2.add(0.602);
    al2.add(0.373);
    a.add(al2, null);


    al3.add(0.628);
    al3.add(0.193);
    al3.add(0.810);
    al3.add(0.000);
    al3.add(0.855);
    al3.add(0.599);
    al3.add(0.382);
    a.add(al3, null);


    al4.add(0.243);
    al4.add(0.258);
    al4.add(-0.276);
    al4.add(-0.538);
    al4.add(0.041);
    al4.add(-0.192);
    al4.add(0.025);
    a.add(al4, null);


    al5.add(0.134);
    al5.add(0.281);
    al5.add(0.529);
    al5.add(0.305);
    al5.add(0.459);
    al5.add(0.186);
    al5.add(0.411);
    a.add(al5, null);





    Bartlett b = new Bartlett(a);

    try {
      double chi = new Pocitani().getChiKritickaHodnota(4, 0.95);
      System.out.println((b.getB() < chi)? "H0 nezamitame. Let`s go Anova." : "H0 zamitnuta. At zije HA");
      if (b.getB() < chi) {
        Anova anova = new Anova(a);
        boolean HA = (anova.getTestovaStatistika() > (new Pocitani().getFKritickaHodnota(4, 30, 0.95)));
        if (HA) {
          Scheffe sch = new Scheffe(anova);
          System.out.println(sch.vypis());
        }

      }
    } catch (Exception e) {
      e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
    }


  }
}

